const OPERATE_DEPLOY = async args => {

	const {curry,fingerPrint,amount,file,size=1} = args;

	const puzzle = Puzzle.of(file).curryList(curry);

	const coins = puzzle.getUnSpentCoins(amount);

	const deployCoins = async ()=>{
		const transaction = puzzle.deploy(fingerPrint,amount)
		const coin = await transaction.getCoin()
		return [puzzle,coin]
	}

	//deploy pattern
	if(__isDeploy__ > 0){

		const _deployCoins =[]
		for(var i=0;i<size;i++){
			const [p,c] = await deployCoins()
			_deployCoins.push(c)
		}
		return [puzzle,_deployCoins[0],_deployCoins]
	}else{

		if(coins.length >= size){
			return [puzzle,coins[0],coins.slice(0,2)]
		}
		await deployCoins()
		return await OPERATE_DEPLOY(args)
		
	}


}


const SEARCH_COINS = ({puzzleHash,minAmount,isStrict=true}) => {

	let coinlist = new PuzzleCurryOperate({treehash:puzzleHash}).getUnSpentCoins();


	const _aggregateCoin = (arry,sum=0,out=[],index=0) => {
		if(index >= arry.length || sum >= minAmount)
			return out;

		const coin = arry[index];

		return _aggregateCoin(arry,sum+coin.getAmount(),[...out,coin],index+1)
	}

	const findCoins = _aggregateCoin(coinlist)

	const totalAmount = findCoins.map(v => v.getAmount()).sum()

	//const ssum = coinlist.map(v => v.getAmount()).sum()

	//console.log({ssum,puzzleHash,findCoins,totalAmount,minAmount,tt:totalAmount-minAmount})

	if(isStrict){

		if(findCoins == 0)
			throw `not find coins puzzleHash:${puzzleHash}`

		if(totalAmount < minAmount)
			throw `do not have enough amount puzzlehash:${puzzleHash}`
	}

	return [findCoins,totalAmount]
}



const WRAP_STANDARD_COIN = ({puzzleHash,amount,fee=0}) => {

	const  [findCoins,totalAmount] = SEARCH_COINS({puzzleHash,minAmount:amount+fee});

	return new WrapStandardCoin(findCoins.map(c => new StandardCoin(c)),amount,fee)

}


const DEPLOY_SMART_COIN = async ({file,curry=[],amount=1,fee=0,nemonicData}) => {
	
	nemonicData = nemonicData || _MNEMONIC;
	
	if(!nemonicData)
		throw 'the nemonic must exist!'

	const {$ph,$sk} = nemonicData;

	const programe = Puzzle.of(file).curryList(curry);

	//driver pattern 
	if(__isDeploy__ == 0){

		let existCoins = programe.getUnSpentCoins(amount);

		if(existCoins.length > 0)
			return [programe,existCoins[0],existCoins]
    }

	const wrapCoin = WRAP_STANDARD_COIN({puzzleHash:$ph,amount,fee})

	await wrapCoin.setSolution([
		[OPC_CODE.CREATE_COIN,programe.getPuzzleHash(),amount]
	],$sk);

	await wrapCoin.doSpent().print();
	
	const coins = programe.getUnSpentCoins(amount);

	return [programe,coins[0]]

}

//find already deploy coins
const _paramFindCoins = param => {
	const {file,curry=[],amount} = param;
	const programe = Puzzle.of(file).curryList(curry);
	const coins = programe.getUnSpentCoins(amount);
	return coins.length > 0 ? [programe,coins[0],coins] : null;
}

const _getAllSolution = (params,allOuts=[],index=0) => {

	if(index >= params.length)
		return allOuts;

	const {file,curry=[],amount} = params[index];
	const programe = Puzzle.of(file).curryList(curry);

	allOuts.push([OPC_CODE.CREATE_COIN,programe.getPuzzleHash(),amount])

	return _getAllSolution(params,allOuts,index+1);
}

const DEPLOY_SMART_COIN_LIST = async (params,fee=0,nemonicData) => {

	//driver pattern!
	if(__isDeploy__ == 0){
		const findCoins = params.map(_paramFindCoins).filter(v => v)
		if(findCoins.length == params.length)
			return findCoins;
	}

	nemonicData = nemonicData || _MNEMONIC;
	
	if(!nemonicData)
		throw 'the nemonic must exist!'

	const {$ph,$sk} = nemonicData;

	const deployAllAmount = params.map(v => v.amount*(v.size || 1)).sum();

	const wrapCoin = WRAP_STANDARD_COIN({puzzleHash:$ph,amount:deployAllAmount,fee})

	const allSolution = _getAllSolution(params)

	await wrapCoin.setSolution(allSolution,$sk);

	await wrapCoin.doSpent().print();

	return params.map(_paramFindCoins);
}



